#ifndef HASH_H
#define HASH_H

#include "glm/glm.hpp"
#include "prime.h"
#include "Sphere.h"

/* 3 very large primes used for hash function */
#define PRIME_1 73856093
#define PRIME_2 19349663
#define PRIME_3 83492791



/* only using x, y, z for now.
 * the positions of the Spheres
 */
typedef struct Part {
    glm::vec3 pos;
    int id;

    Part() {
        pos = glm::vec3(0.f);
        id = 0;
    }
} Particle;

typedef struct L_HNode {
    L_HNode *next;
    Sphere *p;
    bool filled;

    L_HNode() {
        next = NULL;
        p = NULL;
        filled = false;
    }

    ~L_HNode() {
        //delete p;
        if (next)
            delete next;
    }
} HNode;

void print_Sphere(Sphere *p);
void print_list(HNode *n);

typedef struct HashTable {
    HNode *nodes;
    int size;
    float dist;

    void insert(Sphere *p);
    void remove(Sphere *p);
    void clean();

    HNode *lookUp(float x, float y, float z);
    HNode *lookUpId(float x, float y, float z, int id);
    HNode *cull(HNode *list, glm::vec3 v, int id);

    int hash(glm::vec3 v);
    bool exists(float x, float y, float z);
    bool find(float x, float y, float z);
    bool matches(HNode *list, glm::vec3 v);

    HashTable(int n, float h) {
        size = next_prime(2 * n);
        nodes = (HNode *) calloc(sizeof(HNode), size);

        dist = h;
    }

    ~HashTable() {
        int i;
        HNode *temp1, *temp2;

        for (i = 0; i < size; i++) {
            if (nodes[i].next)
                delete nodes[i].next;
          /*  if (nodes[i].next) {
                temp1 = nodes[i].next;
                temp2 = temp1->next;
                
                while (temp1) {
                    delete temp1;
                    temp1 = temp2;
                    if (temp1) 
                        temp2 = temp2->next;
                }
            }*/
        }
        
        free(nodes);
    }
} HashTable;

#endif
